package com.why.config.security;


import com.why.util.JwtTokenUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * 登录成功后 走此类进行鉴权操作
 */
public class FormLoginAuthorizationFilter extends BasicAuthenticationFilter {


//    private ResourceRepository resourceRepository;

    public FormLoginAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }


    /**
     * 在过滤之前和之后执行的事件
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String tokenHeader = request.getHeader(JwtTokenUtil.TOKEN_HEADER);

        // 若请求头中没有Authorization信息 或是Authorization不以Bearer开头 则直接放行
        if (tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtil.TOKEN_PREFIX)) {
            // 处理编码方式 防止中文乱码
            response.setContentType("text/json;charset=utf-8");
            response.getWriter().write("token参数必传！！！");

            return;
        }

        // 去掉前缀 获取Token字符串
        String token = tokenHeader.replace(JwtTokenUtil.TOKEN_PREFIX, "");

        if (JwtTokenUtil.isExpiration(token)) {
            // 处理编码方式 防止中文乱码
            response.setContentType("text/json;charset=utf-8");
            response.getWriter().write("token过期");
            return;
        }

        // 从Token中解密获取用户名
        String username = JwtTokenUtil.getUsername(token);
        // 从Token中解密获取用户角色
        String role = JwtTokenUtil.getUserRole(token);
        // 将[ROLE_XXX,ROLE_YYY]格式的角色字符串转换为数组
        String[] roles = StringUtils.strip(role, "[]").split(", ");

        //todo 检查用户是否拥有访问路径的权限

        if (roles.length == 0) {
            response.setContentType("text/json;charset=utf-8");
            response.getWriter().write("用户无权限");
            return;
        }
        //如果拥有admin权限则放行
//        if (Arrays.stream(roles).noneMatch(item -> item.equals("ADMIN"))) {
//            //查询用户可访问的资源路径
////            List<Resources> resourceList = resourceRepository.findByUserName(username);
//            if (resourceList.isEmpty()) {
//                response.setContentType("text/json;charset=utf-8");
//                response.getWriter().write(JSON.toJSONString(Result.fail("权限不足")));
//                return;
//            }
//            Set<String> resource = resourceList.stream().map(Resources::getUrl).collect(Collectors.toSet());
//            String requestURI = request.getRequestURI();
//            //如果用户拥有的资源路径不包含请求路径则返回
//            if (resource.stream().noneMatch(it -> it.equals(requestURI))) {
//                // 处理编码方式 防止中文乱码
//                response.setContentType("text/json;charset=utf-8");
//                response.getWriter().write(JSON.toJSONString(Result.fail("权限不足")));
//                return;
//            }
//
//        }

        // 若请求头中有token 则调用下面的方法进行解析 并设置认证信息
        SecurityContextHolder.getContext().setAuthentication(getAuthentication(username, roles));
        super.doFilterInternal(request, response, chain);
    }


    /**
     * 从token中获取用户信息并新建一个token
     *
     * @param
     * @return 带用户名和密码以及权限的Authentication
     */
    private UsernamePasswordAuthenticationToken getAuthentication(String username, String[] roles) {

        Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (String s : roles) {
            authorities.add(new SimpleGrantedAuthority(s));
        }
        if (username != null) {
            return new UsernamePasswordAuthenticationToken(username, null, authorities);
        }
        return null;
    }

}
